/**
 * Copyright (C) 2011 GreenSoft S.A.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.com.greensoft.neosystem.dao.jpa;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import ar.com.greensoft.neosystem.dao.DaoException;
import ar.com.greensoft.neosystem.dao.searching.DtoSearchableDao;
import ar.com.greensoft.neosystem.dao.searching.SortCriteria;
import ar.com.greensoft.neosystem.search.SearchFilter;

/**
 * 
 * @author Jorge E. Villaverde
 * @since 1.0.0
 * @version 1.0.0
 */
public abstract class AbstractJpaDaoDtoImpl<T, PK extends Serializable, Dto extends Serializable> 
	extends AbstractJpaDaoImpl<T, PK>
	implements DtoSearchableDao<Dto>{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public long countDto() throws DaoException {
		return count();
	}

	@Override
	public long countDtoBySearchFilter(SearchFilter filter) throws DaoException {
		return countBySearchFilter(filter);
	}
	
	@Override
	public List<Dto> findDtoEntries(int startPosition, int maxResult, List<SortCriteria> sortCriterias) throws DaoException {
		return findDtoEntriesBySearchFilter(null, startPosition, maxResult, sortCriterias);
	}
	
	@Override
	public List<Dto> findDtoEntriesBySearchFilter(SearchFilter filter, 
			int startPosition, int maxResult,
			List<SortCriteria> sortCriterias) throws DaoException {
		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();

		Class<T> entityClazz = getEntityClazz();
		Class<Dto> dtoClazz = getDtoClazz(); 
				
		CriteriaQuery<Dto> criteriaQuery = builder.createQuery(dtoClazz);
		Root<T> root = criteriaQuery.from(entityClazz);
		
		criteriaQuery.select(createDtoBuilder(builder, root));
		Expression<Boolean> predicate = createWhereFromSearchFilter(filter, root);
		
		if(predicate != null)
			criteriaQuery.where(predicate);

		List<Order> orders = createEntityOrders(builder, 
				getExpressionMap(root), 
				sortCriterias);
		
		if(orders == null)
			orders = createOrders(root);
		if(orders != null)
			criteriaQuery.orderBy(orders);
	
		TypedQuery<Dto> typedQuery = getEntityManager().createQuery(criteriaQuery);
		
		return typedQuery.setFirstResult(startPosition).setMaxResults(maxResult).getResultList();
	}	
	
	// Abstract Methods
	protected abstract Class<Dto> getDtoClazz();

	protected abstract Selection<? extends Dto> createDtoBuilder(CriteriaBuilder builder, Root<T> root);	
	
	protected abstract Map<String, Expression<?>> getExpressionMap(Root<T> root);
}
